<?php
/**
 * 入库操作类, 继承多线程库
 */
class Storage extends Thread{
    /**
     * hash值
     * @var string
     */
    private $hash;
    /**
     * 资源热度
     * @var integer
     */
    private $hot;
    /**
     * 本地保存路径
     * @var string
     */
    private $filepath;
    /**
     * 下载计数
     * @var integer
     */
    private $t = 0;

    /**
     * 构造函数, 初始化数据
     * @param string $hash 传入要下载的hash
     * @param integer $hot 资源热度
     */
    public function __construct($hash, $hot){
        $this->hash = $hash;
        $this->hot = $hot;
        $db = new DB;
        // 判断此infohash是否存在于torrage.com中, 存在则直接在torrage.com中下载
        $this->t = ($db->check($this->hash, true)) ? 0 : 1;
        $db->close();
        $this->filepath = ABSPATH . '/torrent/' . $hash . '.torrent';
    }

    /**
     * 运行调用方法, 执行入库操作
     * @return void
     */
    public function run(){
        // 检测是否下载成功
        if(!$this->down_torrent())
            return @exec('rm -f ' . $this->filepath);

        // 检测种子是否读取成功
        if(!$btinfo = $this->read_torrent()){
            // 如果读取失败, 使用下一个地址下载试试
            return $this->down_torrent($this->t++);
        }

        // 将hash加入种子信息中
        $btinfo['infohash'] = $this->hash;
        // 将热度加入种子信息中
        $btinfo['hot'] = $this->hot;

        // 初始化数据库
        $db = new DB;
        // 将种子信息写入数据库
        $db->insert($btinfo);
        // 关闭数据库链接
        $db->close();

        // 将下载的文件删除
        @exec('rm -f ' . $this->filepath);
    }

    /**
     * 下载种子文件方法
     * @return boolean 返回是否下载成功
     */
    private function down_torrent(){
        switch($this->t){
            case 1:
                $url = 'http://bt.box.n0808.com/' . substr($this->hash, 0, 2) . '/' . substr($this->hash, -2) . '/' . $this->hash . '.torrent';
                break;
            case 2:
                $url = 'https://torcache.net/torrent/' . $this->hash . '.torrent';
                break;
            case 3:
                $url = 'http://178.73.198.210/torrent/' . $this->hash . '.torrent';
                break;
            case 4:
                $url = 'http://thetorrent.org/' . $this->hash . '.torrent';
                break;
            case 0:
            default:
                $url = 'https://torrage.com/torrent/' . $this->hash . '.torrent';
        }

        $cp = curl_init($url);
        $fp = fopen($this->filepath,"wb");
        curl_setopt($cp, CURLOPT_FILE, $fp);
        curl_setopt($cp, CURLOPT_HEADER, 0);

        if $this->t == 2 || $this->t == 0{
            curl_setopt($cp, CURLOPT_SSL_VERIFYPEER, FALSE);
            curl_setopt($cp, CURLOPT_SSL_VERIFYHOST, FALSE);
        }

        curl_exec($cp);
        curl_close($cp);
        fclose($fp);

        // 检查本地文件是否存在, 且文件大小是否大于1K
        if(file_exists($this->filepath) && filesize($this->filepath) > 1024)
            return true;

        // 都不行, 返回错误
        return false;
    }

    /**
     * 解析种子文件信息
     * @return boolean 返回是否解析成功
     */
    private function read_torrent(){
        // 读取种子文件信息
        $torrent = new Torrent($this->filepath);
        $Lightbenc = new Lightbenc();
        $light = $Lightbenc->bdecode_getinfo($this->filepath);

        // 若读取出错则返回错误
        if(isset($torrent->info) && !preg_match('/' . $this->hash . '\.torrent/i', $torrent->info['name'])){
            // 获取种子文件名, 若存在utf8格式则使用utf8格式信息
            $btinfo['name'] = isset($torrent->info['name.utf-8']) ? $torrent->info['name.utf-8'] : $torrent->info['name'];
            // 获取种子创建时间
            $btinfo['createtime'] = isset($torrent->{'creation date'}) ? $torrent->{'creation date'} : time();
            // 创建两个临时变量, 用作统计种子文件数及文件大小
            $nums = $size = 0;

            // 检查种子信息中是否包含files项
            if(isset($torrent->info['files'])){
                // 循环处理种子文件列表
                foreach($torrent->info['files'] as $f){
                    // 检查种子是否包含目录信息
                    if(count($f['path']) > 1)
                        // 获取目录+文件信息, 有utf8则使用utf8
                        $path = isset($f['path.utf-8']) ? $f['path.utf-8'][0] . '/' . $f['path.utf-8'][1] : $f['path'][0] . '/' . $f['path'][1];
                    else
                        // 获取文件信息, 有utf8则使用utf8
                        $path = isset($f['path.utf-8']) ? $f['path.utf-8'][0] : $f['path'][0];

                    // 将文件信息加入列表
                    $btinfo['list'][] = array(
                        'file' => $path,
                        'length' => $f['length']
                    );

                    // 文件计数+1
                    $nums++;
                    // 加上文件大小
                    $size += $f['length'];
                }
            // 若不存在文件列表
            }else{
                // 文件数为1
                $nums = 1;
                // 设置文件大小
                $size = $torrent->info['length'];
            }

            // 设置种子大小
            $btinfo['length'] = $size;
            // 设置种子文件数
            $btinfo['filecount'] = $nums;

            // 如果获取到的种子信息内容大于或等于4项, 且种子文件大小大于1M, 证明获取成功, 否则返回错误
            return (count($btinfo) >= 4 && $size > 1048576) ? $btinfo : false;
        }elseif(isset($light['info'])){
            // 获取种子文件名, 若存在utf8格式则使用utf8格式信息
            $btinfo['name'] = isset($light['info']['name.utf-8']) ? $light['info']['name.utf-8'] : $light['info']['name'];
            // 获取种子创建时间
            $btinfo['createtime'] = isset($light['creation date']) ? $light['creation date'] : time();
            // 创建两个临时变量, 用作统计种子文件数及文件大小
            $nums = $size = 0;

            // 检查种子信息中是否包含files项
            if(isset($light['info']['files'])){
                // 循环处理种子文件列表
                foreach($light['info']['files'] as $f){
                    // 检查种子是否包含目录信息
                    if(count($f['path']) > 1)
                        // 获取目录+文件信息, 有utf8则使用utf8
                        $path = isset($f['path.utf-8']) ? $f['path.utf-8'][0] . '/' . $f['path.utf-8'][1] : $f['path'][0] . '/' . $f['path'][1];
                    else
                        // 获取文件信息, 有utf8则使用utf8
                        $path = isset($f['path.utf-8']) ? $f['path.utf-8'] : $f['path'];

                    // 将文件信息加入列表
                    $btinfo['list'][] = array(
                        'file' => $path,
                        'length' => $f['length']
                    );

                    // 文件计数+1
                    $nums++;
                    // 加上文件大小
                    $size += $f['length'];
                }
            // 若不存在文件列表
            }else{
                // 文件数为1
                $nums = 1;
                // 设置文件大小
                $size = $light['info']['length'];
            }

            // 设置种子大小
            $btinfo['length'] = $this->convert($size);
            // 设置种子文件数
            $btinfo['filecount'] = $nums;

            // 如果获取到的种子信息内容大于或等于4项, 且种子文件大小大于1M, 证明获取成功, 否则返回错误
            return (count($btinfo) >= 4 && $size > 1048576) ? $btinfo : false;
        }else{
            return false;
        }
    }

    /**
     * 将字节转换为对应的可读性大小
     * @param  integer $size 要转换的字节数
     * @return string       转换后的信息
     */
    private function convert($size){
        // 定义一个数组, 保存对应的数据大小
        $unit = array('B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB');
        // 临时变量
        $i = 0;
        // 数据转换标准
        $inv = 1 / 1024;

        // 循环转换
        while($size >= 1024 && $i < 8){
            $size *= $inv;
            ++$i;
        }

        // 对数据进行格式化
        $t = sprintf("%.2f", $size);

        // 返回转换后的数据
        return ($t - (int)$t ? $t : $size) . $unit[$i];
    }
}